#!/bin/sh
# Bug reports and comments to Igor.Ermolaev@intel.com
base=$(dirname $(readlink -f ${BASH_SOURCE[0]:-$0}))
margin=32768
module="$1";shift
unset ofs
re=':-?(0x)?[0-9a-fA-F]+$';if [[ "$module" =~ $re ]]; then
   r=( `echo $module|tr ':' ' '` )
   module=${r[0]}
   ofs=$((r[1]))
fi
ladr=`echo "$module"|sed -n 's/^.*+\(\(0x\)\?\([0-9A-Fa-f]\+\)\)$/\1/p'`
if [ -n "$ladr" ]; then module="${module%+*}"; fi

unset min max
expand=false;funcs=false
if [ "$1" == '-r' ]; then
   range=true;shift
elif [ `$base/binutils/bin/objdump -h $module|grep -c '.debug'` -eq 0 ]; then
   range=true
else
   range=false
fi

re_0xP='^0x[0-9a-fA-F]+(:[0-9]+)?$'
re_blk='^(0x)?[0-9a-fA-F]+(:[0-9]+)?$'
re_src='^[^:]+(:[0-9]+)?$'
exl_syms='\s\+\.debug\|\s\+t\s\+\.\|\s\+t\s\+L[0-9]\+$\|\s\+t\s*$\|\$\$LSDA$'
while [ $# -ne 0 ]; do
   if ( [ $range == false ] || ! [[ "$1" =~ $re_0xP ]] ) && [[ "$1" =~ ^[^:]+$ ]]; then
      saveIFS=$IFS;IFS='
';       addrs=( `$base/binutils/bin/nm -n "$module"|uniq -w 16|grep -v "$exl_syms"|grep -A 1 -P '\s\Q'"$1"'\E$'|grep '^--$' -v|awk '{print strtonum("0x"$1)}'` ) # exact match
         if [ ${#addrs[@]} -ne 2 ];then
            key=`echo "$1"|tr [:upper:] [:lower:]`
            for (( ctx=1; ; ctx++ )); do
               addrs=( `$base/binutils/bin/nm -n "$module"|grep -v "$exl_syms"|tr [:upper:] [:lower:]|uniq|grep -A $ctx -P '(_mp_|\s)\Q'"$key"'\E[_]*(\.|\d)*$'|grep '^--$' -v|awk '{print strtonum("0x"$1)}'` )
               if [ ${#addrs[@]} -eq 0 ]; then
                  addrs=( `$base/binutils/bin/objdump -Wi -w $module 2>/dev/null|grep -A 10 -P '\s+DW_AT_name\s+.*:\s+\Q'"$1"'\E'|grep 'low_pc\|high_pc'|awk '{print strtonum($4)}'` )
               elif [ ${#addrs[@]} -ge $(( ctx + 1 )) ] && [ ${addrs[0]} -eq ${addrs[${#addrs[@]}-1]} ]; then
                  continue
               fi
               break
            done
         fi
      IFS=$saveIFS
      if [ ${#addrs[@]} -ne 0 ]; then
         for a in "${addrs[@]}"; do
            if [ -n "$ofs" ]; then a=$(($a+$ofs)); fi
            if [ -z "$min" ] || [ $a -lt $min ]; then min=$a; fi
            if [ -z "$max" ] || [ $a -gt $max ]; then max=$a; fi
         done
         expand=false;funcs=true
         shift;continue
     fi
   fi
   if [[ "$1" =~ $re_blk ]]; then
      if [ $range == true ] && [ $funcs == false ]; then
         save_IFS=$IFS;IFS=':';r=($1);IFS=$save_IFS
         r[0]=$((r[0]))
         if [ -z "$min" ] || [ ${r[0]} -lt $min ]; then min=${r[0]}; fi
         if [ -z "${r[1]}" ]; then addr=${r[0]}; else addr=$((r[0]+r[1]-1)); fi
         if [ -z "$max" ] || [ $addr -gt $max ]; then max=$addr; fi
         expand=true
      fi
   elif [[ "$1" =~ $re_src ]]; then
      if [ $funcs == false ]; then
         saveIFS=$IFS;IFS='
';addrs=( `$base/binutils/bin/objdump -WL -w $module 2>/dev/null|grep -P '(^|\s|\/)\Q'${1%:*}'\E\s+\Q'"${1##*:}"'\E(\s|$)'|awk '{print strtonum($3)}'` );IFS=$saveIFS
         for a in "${addrs[@]}"; do
            if [ -n "$ofs" ]; then a=$(($a+$ofs)); fi
            if [ -z "$min" ] || [ $a -lt $min ]; then min=$a; fi
            if [ -z "$max" ] || [ $a -gt $max ]; then max=$a; fi
         done
         expand=true
      fi
   fi
   shift
done
if [ $expand == true ]; then
   if [ -n "$min" ]; then
      min=`echo "scale=0;t=($min-$margin/2-$margin/4)/$margin;t=t*$margin;if(t<0)0 else t"|bc`
   fi
   if [ -n "$max" ]; then
      max=`echo "scale=0;t=($max+$margin/2+$margin/4+$margin-1)/$margin;t*$margin"|bc`
   fi
elif [ -n "$min" ] && [ -n "$max" ] && [ $min -eq $max ]; then 
   unset max
fi

if [ -x $base/binutils.lrb2/bin/objdump ] && [ `$base/binutils/bin/strings -a $module|grep -m 1 -w 'Larrabee\|[^\]lrb2[^\]\|branch_lrb' -ic` -gt 0 ]; then sfx=.lrb2; fi
if [ -n "$min" ] || [ -n "$max" ]; then
   exec $base/etc/cached 4 5 $base/binutils$sfx/bin/objdump -d -l -w --no-show-raw-insn $module${ofs:+ --adjust-vma=$ofs}${min:+ --start-address=$min}${max:+ --stop-address=$max}
elif [ $funcs != true ]; then
   exec $base/etc/cached 4 5 $base/binutils$sfx/bin/objdump -d -l -w --no-show-raw-insn $module${ofs:+ --adjust-vma=$ofs}
fi
